#pragma once

#ifndef __CORE_StrIdMgr_H__
#define __CORE_StrIdMgr_H__

#include "FLOW_core/namespace.h"
#include "FLOW_core/hash_funcs.h"
#include "FLOW_core/Mutex.h"

#define STRIDMGR	CORE::CStrIdMgr::GetInstance( )

namespace CORE
{
	/*!
	 * \brief This singleton manager is responsible for storing the real strings hashed in the StrIds.
	 *
	 * This singleton manager is responsible for storing the real strings hashed in the StrIds and perform
	 * reference counting on those strings to free them when no needed anymore.
	 * 
	 * The optimization of memory that this manager tries to perform depends on the users of this code
	 * don't define static literal strings. For each one of those defined a copy will be in the executable
	 * file code and another copy in the CStrIdMgr, so try to put all the strings into the application reading
	 * them from file or any other stream or using user input.
	 */
	class CStrIdMgr
	{
	private:
		//========================= DATA TYPE DEFINITIONS =====================

		//! Struct that holds the real strings, it's reference counted
		struct TStringHolder : public CRefCounted
		{
		private:
			const char_t*			m_psz_s;

		public:
			//! Default constructor
			TStringHolder( );

			//! Destructor
			~TStringHolder( );

			//! Stores the string
			void Set( const char_t* apsz_s );

			//! Equality operator
			bool_t operator == ( const TStringHolder& ar_str_holder );
			bool_t Equals( const TStringHolder& ar_str_holder );
			bool_t Equals( const char_t* ap_sz );

			//! Returns the string contained
			const char_t* c_str( void );
		};

		//! String container typedef
		typedef CHashMap< hashid_t, TStringHolder*, std::hash< hashid_t > > TSzHashMap;

		//============================= DATA MEMBERS ==========================

		//! hash map that contains all the strings associated to its hash value
		TSzHashMap				m_hm_strids;

		//! Reference to the unique instance of the manager
		static CStrIdMgr*		sg_p_strid_mgr;

		//! mutex to make the access to the strings hash map multi-threading safe
		CMutex					m_mutex;

	private:
		//=============================== METHODS =============================

		//! Constructor
		CStrIdMgr( );

		//! Destructor
		~CStrIdMgr( );

		//! Copy constructor
		CStrIdMgr( const CStrIdMgr& ar_strid_mgr );

		//! Assignment operator
		CStrIdMgr& operator = ( const CStrIdMgr& ar_strid_mgr );

	public:
		//=============================== METHODS =============================

		//! Static member to get the unique instance of the CStrIdMgr
		static CStrIdMgr* GetInstance( void );

		//! Adds a string to the string database and returns its hash value
		bool_t AddString( const char_t* apsz_s, hashid_t& ar_hash );

		//! Adds a reference to the string identified by the hash code passed if exists
		bool_t AddString( hashid_t& ar_hash );

		//! Release a string from the database, it's only deleted when its reference count reaches 0. 
		//! It returns the number of references after releasing
		u32_t ReleaseString( hashid_t a_h );

		//! Finds a string by its hash value
		const char_t* GetString( hashid_t a_h );

	};
} //namespace CORE

#endif